using System.Collections.Generic;
using System.Threading;

namespace OracleInternal.Common
{
	internal class Pooler<keyType, valType>
	{
		private object m_sync;

		private ulong m_lastUsedCount;

		private PoolerItemOwnership m_ownership;

		private SortedDictionary<keyType, PoolMember<valType>> m_cache;

		public int m_maxCacheSize;

		public int m_maxSubCacheSize;

		public Pooler(int maxCacheSize, int maxSubCacheSize, PoolerItemOwnership ownership)
		{
			m_sync = new object();
			m_maxCacheSize = maxCacheSize;
			m_maxSubCacheSize = maxSubCacheSize;
			m_lastUsedCount = 1uL;
			m_ownership = ownership;
			m_cache = new SortedDictionary<keyType, PoolMember<valType>>();
		}

		internal bool Remove(keyType key)
		{
			return m_cache.Remove(key);
		}

		internal PoolMember<valType> RemoveLRU()
		{
			ulong num = ulong.MaxValue;
			keyType key = default(keyType);
			SortedDictionary<keyType, PoolMember<valType>>.Enumerator enumerator = m_cache.GetEnumerator();
			while (enumerator.MoveNext())
			{
				ulong lastUsedTime = enumerator.Current.Value.m_LastUsedTime;
				if (lastUsedTime < num)
				{
					key = enumerator.Current.Key;
					num = lastUsedTime;
				}
			}
			PoolMember<valType> result = m_cache[key];
			m_cache.Remove(key);
			return result;
		}

		public virtual valType Put(keyType key, valType val)
		{
			PoolMember<valType> value = null;
			lock (m_sync)
			{
				m_cache.TryGetValue(key, out value);
				if (value != null)
				{
					if (value.m_list.Count < m_maxSubCacheSize)
					{
						value.m_list.Add(val);
						return default(valType);
					}
					return val;
				}
				if (m_cache.Count >= m_maxCacheSize)
				{
					value = RemoveLRU();
					valType result = default(valType);
					if (value.m_list.Count > 0)
					{
						result = value.m_list[0];
					}
					value.m_list.Clear();
					value.m_list.Add(val);
					value.m_LastUsedTime = m_lastUsedCount++;
					m_cache[key] = value;
					return result;
				}
				value = new PoolMember<valType>(val, m_maxSubCacheSize, m_lastUsedCount++);
				m_cache[key] = value;
				return default(valType);
			}
		}

		public valType Get(keyType key)
		{
			PoolMember<valType> value = null;
			if (m_ownership == PoolerItemOwnership.Exclusive)
			{
				Monitor.Enter(m_sync);
			}
			try
			{
				m_cache.TryGetValue(key, out value);
				if (value != null)
				{
					if (value.m_list.Count > 0)
					{
						valType val = value.m_list[0];
						if (m_ownership == PoolerItemOwnership.Exclusive)
						{
							value.m_list.Remove(val);
						}
						value.m_LastUsedTime = m_lastUsedCount++;
						return val;
					}
					return default(valType);
				}
				return default(valType);
			}
			finally
			{
				if (m_ownership == PoolerItemOwnership.Exclusive)
				{
					Monitor.Exit(m_sync);
				}
			}
		}

		public bool ContainsKey(keyType key)
		{
			try
			{
				return m_cache.ContainsKey(key);
			}
			catch
			{
				return false;
			}
		}
	}
}
